/**
 * 2010(c) www.jcaramel.com
 * LISTVIEW
 * 
 * Requires: jCaramel-Core
 */
//ListView namespace functions
jCaramel.listView = {
		
		/**
		 * Initializes a listview
		 * @param {Object} lsv
		 * @param {Object} settings
		 */
		_create: function(lsv, settings){
			
			var items = jCaramel.listView.items(lsv);
			var firstColumnIncrement = 0;
			
			//Assign handle
			jCaramel.createHandle(lsv);
			
			//Hide sub-lists
			lsv.find('ul').css('background', 'red').hide();
			
			//Make focusable
			lsv.attr('tabindex', 0);
			
			//Add necessary classes to the ul
			lsv.addClass('scrollable-view');
			lsv.addClass('listview');
			
			//Add checkboxes tagclass
			lsv.flag('checkboxes', settings.checkboxes);
			
			//Add iconsize tag
			lsv.tag('iconSize', settings.iconSize);
			
			//Set column headers
			jCaramel.listView.columnHeaders(lsv, settings.columns);
			
			//Set checkboxes visiblity
			jCaramel.listView.checkboxes(lsv, settings.checkboxes);
			
			//Set view-mode
			jCaramel.listView.mode(lsv, settings.mode);
			
			//Assign event handlers to items
			jCaramel.listView.assignItemHandlers(lsv, items);
							
			lsv
				//Scroll handler for column headers
				.unbind('scroll')
				.scroll(jCaramel.listView.listView_Scroll)
				
				//Key up and down handlers
				.unbind('keydown')
				.keydown(jCaramel.listView.listView_KeyDown);
				
			if (settings.hideColumns) {
				setTimeout('jCaramel.listView.columnHeadersVisible(jCaramel.getByHandle(' + lsv.tag('handle') + '), false)', 100, this);
				
			}
			
			if(settings.tree)
				jCaramel.listView.tree(lsv, true);
				
			//Events
			[
				'itemClick', 'itemActivate', 
				'itemMouseEnter', 'itemMouseLeave',
				'fold', 'unfold',
				'columnResizing', 'columnResize', 'columnSort',
				'columnHeaderMouseEnter', 'columnHeaderMouseLeave',
				'itemCheck', 'itemUncheck', 'checkChange'
			].forEach(function(evtName){ jCaramel.bind(lsv, evtName, settings[evtName]); });
			
		},//End _create
		
		/**
		 * Assigns handlers to specified list-items
		 * @param {jQuery} lsv ListView where items belong
		 * @param {jQuery} items Items to assign handlers
		 */
		assignItemHandlers: function(lsv, items){
			
			if(typeof(items) == 'undefined'){
				items = jCaramel.listView.items(lsv);
			}
			
			//Add click handlers for listview-item clicks
			items
				.unbind('mousedown', jCaramel.listView.item_MouseDown)
				.mousedown(jCaramel.listView.item_MouseDown)
				
				.unbind('selectionstart', jCaramel.listView.item_MouseDown)
				.bind('selectionstart', jCaramel.listView.item_MouseDown) //Avoiding selection for IE
				
				.unbind('mouseenter', jCaramel.listView.item_MouseEnter)
				.mouseenter(jCaramel.listView.item_MouseEnter)
				
				.unbind('mouseleave', jCaramel.listView.item_MouseLeave)
				.mouseleave(jCaramel.listView.item_MouseLeave)
				
				.unbind('click', jCaramel.listView.item_Click)
				.click(jCaramel.listView.item_Click)
				
				.unbind('dblclick', jCaramel.listView.item_DoubleClick)
				.dblclick(jCaramel.listView.item_DoubleClick)
				
				;
				
			//Add click handlers to checkboxes
			items.find('.glyph-checkbox-unchecked, .glyph-checkbox-checked')
				.unbind('click')
				.click(jCaramel.listView.checkbox_Click);
			
			//Add handlers to tree-glyphs
			items.find('.tree-glyph')
				.unbind('mouseenter')
				.mouseenter(jCaramel.listView.treeGlyph_MouseEnter)
				
				.unbind('mouseleave')
				.mouseleave(jCaramel.listView.treeGlyph_MouseLeave)
				
				.unbind('click')
				.click(jCaramel.listView.treeGlyph_Click);
		},
		
		/**
		 * Handles clicks on checkboxes
		 * @param {Object} evt
		 */
		checkbox_Click: function(evt){
			var b = jQuery(this);
			var li = b.parents('li');
			if (b.hasClass('glyph-checkbox-unchecked')){
				b.removeClass('glyph-checkbox-unchecked').addClass('glyph-checkbox-checked');
				li.addClass('checked');
			}else{
				b.removeClass('glyph-checkbox-checked').addClass('glyph-checkbox-unchecked');
				li.removeClass('checked');
			}
		},
		
		/**
		 * Sets or gets the visibility of checkboxes
		 * @param {Object} listview
		 * @param {bool} visiblity Value indicating if checkboxes should be displayed
		 * @return {bool} True if checkboxes are enabled, false if not.
		 */
		checkboxes: function(listview, visibility){
			
			if (typeof(visibility) == 'boolean') {
				var items = listview.find('li:not(.column-headers):not(.node)');	
				
				listview.flag('checkboxes', visibility);
				
				//Remove checkboxes
				items.find('.glyph-checkbox-unchecked, .glyph-checkbox-checked').remove();
				
				//Add checkboxes
				if(visibility){
					items.prepend( jQuery('<div>').addClass('glyph-16 glyph-checkbox-unchecked lefty') );
					
					//Add hanlders
					jCaramel.listView.assignItemHandlers(listview, items);
				}
				
				jCaramel.listView.updateColumnHeaderSize(listview);

			}
			else {
				return listview.flag('checkboxes');
			}
		},
		
		/**
		 * Gets or sets the checked items on the list
		 * @param {Object} listview ListView to check for items
		 * @param {Object} items	Items to be checked (Null if getting)
		 * @return {jQuery} Checked items
		 */
		checkedItems: function(listview, items){
			if (!items) {
				return listview.find('li.checked');
			}else{
				//Remove all checked items
				listview.find('.glyph-checkbox-checked').removeClass('.glyph-checkbox-checked').addClass('.glyph-checkbox-unchecked');
				listview.find('li.checked').removeClass('checked');
				items.find('.glyph-checkbox-unchecked').removeClass();
			}
		},
		
		/**
		 * Handles column headers clicks
		 * @param {Object} columnHeader
		 */
		columnHeader_Click: function(evt){
			
			
			var columnHeader = jQuery(this);
			var lsv = columnHeader.parents('.listview');
			var index = columnHeader.parents('.column-headers').first().find('.column-header').index(columnHeader);
			
			if (lsv.flag('just-dragged-column')) {
				lsv.flag('just-dragged-column', false);
				return;
			}
			else {
				jCaramel.listView.sortByColumnHeader(lsv, columnHeader);
				
				jCaramel.fire(lsv, 'columnSort', [index, columnHeader]);
			}
		},
			
		/**
		 * Handles MouseEnter event on columnHeaders
		 * @param {Object} evt
		 */
		columnHeader_MouseEnter: function(evt){
			
			var c = jQuery(this);
			var lsv = c.parents('ul.listview').first();
			var index = c.parents('.column-headers').first().find('.column-header').index(c);
			var grip = c.find('.grip');
			
			grip.addClass('glyph-grip');
			
			jCaramel.fire(lsv, 'columnHeaderMouseEnter', [index, c]);
		},
		
		/**
		 * Handles MouseLeave event on columnHeaders
		 * @param {Object} evt
		 */
		columnHeader_MouseLeave: function(evt){
			var c = jQuery(this);
			var lsv = c.parents('ul.listview').first();
			var index = c.parents('.column-headers').first().find('.column-header').index(c);
			var grip = c.find('.grip');
			
			grip.removeClass('glyph-columnheader-grip');
			
			jCaramel.fire(lsv, 'columnHeaderMouseLeave', [index, c]);
		},
		
		/**
		 * Handles MouseDown event on columnHeaders
		 * @param {Object} evt
		 */
		columnHeaderGrip_MouseDown: function(evt){
			var grip = jQuery(this);
			var col = grip.parents('.column-header').first();
			var lsv = grip.parents('.listview').first();
			var colh = col.parents('.column-headers').first();
			
			lsv.tag('dragging-column', colh.find('.column-header').index(col));
			lsv.mousemove(jCaramel.listView.listView_MouseMove_ColumnHeaderResize);
			lsv.mouseup(jCaramel.listView.listView_MouseUp_ColumnHeaderResize);
			
			return false;
		},
		
		/**
		 * Handles MouseLeave event on columnHeaders grips
		 * @param {Object} evt
		 */
		columnHeaderGrip_MouseMove: function(evt){
			
		},
		
		/**
		 * Handles MouseUp event on columnHeaders grips
		 * @param {Object} evt
		 */
		columnHeaderGrip_MouseUp: function(evt){
			
		},
		
		/**
		 * Gets the column headers of the list view
		 * @param {Object} listview
		 */
		columnHeaders: function(lsv, columns){
			
			var firstColumnIncrement = jCaramel.listView.firstColumnIncrement(lsv);
			
			if (typeof(columns) == 'object' && columns) {
			
				//Create columns if not already there
				lsv.find('li.column-headers').remove();
				
				//Add a LI for column headers
				lsv.prepend(jQuery('<li>').addClass('column-headers'));
				
				//Create column headers
				for (var key in columns) {
					var colh = jQuery('<span>')
						.addClass('column-header')
						.append( jQuery('<div>').addClass('lefty').html(key) )
						.append( jQuery('<div>')
									.addClass('glyph-16 grip righty')
									.css('cursor', 'e-resize')
									.mousedown(jCaramel.listView.columnHeaderGrip_MouseDown)
									.mouseup(jCaramel.listView.columnHeaderGrip_MouseUp)
									.mousemove(jCaramel.listView.columnHeaderGrip_MouseMove) )
						.tag('size', columns[key])
						.mouseenter(jCaramel.listView.columnHeader_MouseEnter)
						.mouseleave(jCaramel.listView.columnHeader_MouseLeave)
						.click(jCaramel.listView.columnHeader_Click);
					lsv.find('.column-headers').append(colh)
				}
				
				//Update size
				jCaramel.listView.updateColumnHeaderSize(lsv);
			}
			else {
				return lsv.find('li.column-headers .column-header');
			}
		},
		
		/**
		 * Gets or sets if the column headers are currently visible
		 * @param {Object} listview
		 * @param {Object} visible
		 */
		columnHeadersVisible: function(listview, visible){
			
			var li = listview.find('li.column-headers');
			if(visible === true || visible === false){
				if(visible){
					li.show();
				}else{
					li.hide();
				}
			}else{
				return li.is(':visible');
			}
		},
		
		/**
		 * Gets the depth of the specified item
		 * @param {Object} listview
		 * @param {Object} item
		 */
		depth: function(listview, ul){
			var d = ul.tag('depth');
			
			if(d && (d != "0")){
				return parseInt(d);
			}else{
				return 0;
			}
		},
		
		/**
		 * Gets the space to be added to the first column of the listview
		 * @param {Object} listview
		 */
		firstColumnIncrement: function(listview){
			var checkboxes = jCaramel.listView.checkboxes(listview);
			var iconSize = jCaramel.listView.iconSize(listview);
			var tree = jCaramel.listView.tree(listview);
			
			return (checkboxes ? 16 : 0) + (tree ? 16 : 0) + iconSize;
		},
		
		/**
		 * Gets the index (zero-based) of the first column of spans
		 * @param {Object} listview
		 */
		firstColumnIndex: function(lsv){
			var iconSize 	= jCaramel.listView.iconSize(lsv);
			var checkboxes 	= jCaramel.listView.checkboxes(lsv);
			var tree		= jCaramel.listView.tree(lsv);
			return (tree ? 1 : 0) + (iconSize ? 1 : 0) + (checkboxes ? 1 : 0) ;
		},
		
		/**
		 * Gets the specified iconSize in creation options
		 * @param {Object} listview
		 * @return {int} Specified iconSize
		 */
		iconSize: function(listview){
			return parseInt(listview.tag('iconSize'));
		},
		
		/**
		 * Gets the items of the listview
		 * @param {Object} listview
		 */
		items: function(listview){
			return listview.find('li:not(.column-headers)');
		},
		
		/**
		 * Handles clicks on items
		 * @param {Object} evt
		 */
		item_Click: function(evt){ 
			evt.stopImmediatePropagation();
			var item = jQuery(this);
			var lsv = item.parents('ul.listview');

			if(evt.shiftKey){
				var pool = lsv.find('li:not(.node):not(.column-headers):visible');
				//selected index
				var selIndex = pool.index(pool.filter('li.selected:first')) + 1;
				var curIndex = pool.index(this);
				var startIndex = 0, endIndex = 0, endoffset = 0;
				
				if(curIndex > selIndex) { startIndex = selIndex; endIndex = curIndex; endoffset = 1; }else{ startIndex = curIndex; endIndex = selIndex; }
				
				//Add selected class to range of items
				pool.filter('li:gt(' + (startIndex - 1) + '):lt(' + (endIndex - startIndex + endoffset) + ')').addClass('selected');
				
			}else{
				//Delete selection from currently selected items (if not ctrl pressed)
				if(!evt.metaKey) lsv.find('li:not(.column-headers)').removeClass('selected');
				
				//Select clicked item
				$(this).addClass('selected'); 
			}
			
			jCaramel.fire(lsv, 'itemClick', [item]);
			
			return false;
		},//End itemClick
		
		/**
		 * Handles double click on items
		 * @param {Object} evt
		 */
		item_DoubleClick: function(evt){
			var li = jQuery(this);
			var lsv = li.parents('ul.listview');
			var g = li.children('.tree-glyph').first();
			
			if(g.size() > 0){
				g.click();
				return false;
			}
			
			jCaramel.fire(lsv, 'itemActivate', [li]);
		},
		
		/**
		 * Hanles the mousedown on items
		 * @param {Object} evt
		 */
		item_MouseDown: function(evt){
			//if(evt.shiftKey){
				return false;
			//}
		},
		
		/**
		 * Handles the mouse enter on items
		 * @param {Object} evt
		 */
		item_MouseEnter: function(evt){
			var item = jQuery(this);
			var lsv = item.parents('ul.listview').first();
			
			if(!item.hasClass('node'))
				item.addClass('hover');
			
			jCaramel.fire(lsv, 'itemMouseEnter', [item]);
		},
		
		/**
		 * Handles the mouse leave on items
		 * @param {Object} evt
		 */
		item_MouseLeave: function(evt){
			var item = jQuery(this);
			var lsv = item.parents('ul.listview').first();
			item.removeClass('hover');
			
			jCaramel.fire(lsv, 'itemMouseLeave', [item]);
		},
		
		/**
		 * Hanles keydown event of listviews
		 * @param {Object} evt
		 */
		listView_KeyDown: function(evt){
			
			var lsv = jQuery(this);
			
			//Result to return
			var result = true;
			
			//Offset for changing selection
			var offsetSelection = 0;
			
			//Set to something if a new item is to be selected
			var newIndex = -1;
			
			//Set to true if user is going down with the keyboard
			var goingDown = false;
			
			//SPACE BAR
			if(evt.which == 32){
				if(jCaramel.listView.checkboxes(lsv)){
					jCaramel.listView.selectedItems(lsv).children('.glyph-checkbox-checked, .glyph-checkbox-unchecked').click();
				}
				result = false;
			}
			
			//UP AND LEFT ARROW KEYS
			if(evt.which == 37 || evt.which == 38){
				offsetSelection =  -1;
			}
			
			//DOWN AND RIGHT ARROW KEYS
			if(evt.which == 39 || evt.which == 40){
				offsetSelection = 1;
				goingDown = true;
			}
			
			var pool = lsv.find('li:not(.node):not(.column-headers):visible');
			
			if(offsetSelection){
				//Calculate new index for selected item
				newIndex = pool.index( pool.filter('li.selected'+ (goingDown ? ':last' : ':first')) ) + offsetSelection;
			}
			
			//Select newIndex only if is a valid index
			if(newIndex >= 0 && newIndex < pool.size() ){
				
				var litem = pool.eq(newIndex);
				
				//Remove selection from previously selected items
				if(!evt.shiftKey) pool.removeClass('selected');
				
				//Select new item
				litem.addClass('selected');
				
				//Ensure new selected item is visible on screen
				jCaramel.ensureVisible(litem, lsv, lsv.find('.column-headers').outerHeight());
				
				result = false; //Return false to cancel further events
			}
		
			
			return result;
		},//End listViewKeyDown
		
		/**
		 * Handles scroll event of listviews
		 * @param {Object} evt
		 */
		listView_Scroll: function(evt){
			$(this).find('li.column-headers').css('top', $(this).scrollTop());	
		},
		
		/**
		 * Hanles MouseMove event on listview when resizing a column header
		 * @param {Object} evt
		 */
		listView_MouseMove_ColumnHeaderResize: function(evt){
			var lsv = jQuery(this);
			var colIndex = lsv.tag('dragging-column');
			var col = jCaramel.listView.columnHeaders(lsv).eq(colIndex);
			var colx = col.offset().left;
			var pagex = evt.pageX;
			
			col.width(pagex - colx);
			col.tag('size', pagex - colx);
			
			var mode = jCaramel.listView.mode(lsv);
			
			if (mode == 'details') {
				var sum = 0;
				var columns = jCaramel.listView.columnHeaders(lsv);
	
				for(var i = 0; i < columns.size(); i++){
					sum += columns.eq(i).outerWidth();
				}
				
				lsv.find('li.column-headers').width(sum);
			}
			
			jCaramel.fire(lsv, 'columnResizing', [colIndex, col]);
			
		},
		
		/**
		 * Handles MouseUp event on listview when resizing a column header
		 * @param {Object} evt
		 */
		listView_MouseUp_ColumnHeaderResize: function(evt){
			var lsv = jQuery(this);
			var colIndex = lsv.tag('dragging-column');
			var col = jCaramel.listView.columnHeaders(lsv).eq(colIndex);
			
			lsv
				.unbind('mousemove', jCaramel.listView.listView_MouseMove_ColumnHeaderResize)
				.unbind('mouseup', jCaramel.listView.listView_MouseUp_ColumnHeaderResize)
				.flag('just-dragged-column', true)
				.tag('dragging-column', '');
			
			jCaramel.listView.updateColumnHeaderSize(lsv);
			
			jCaramel.fire(lsv, 'columnResize', [colIndex, col]);
		},
		
		/**
		 * Sets the mode of the listview
		 * @param {Object} lsv ListView to set mode
		 * @param {Object} mode Mode. Can be 'details', 'tile'
		 */
		mode: function(lsv, mode){

			if( typeof(mode) != 'string'){
				return lsv.tag('mode');
			}

			var computedMode = mode;
			var items = jCaramel.listView.items(lsv);
			var firstColumnIncrement = jCaramel.listView.firstColumnIncrement(lsv);
			var iconSize = jCaramel.listView.iconSize(lsv);
			var checkboxes = jCaramel.listView.checkboxes(lsv);
			
			//Update column headers size
			lsv.find('li.column-headers').css('width', lsv.width() - 20);
			
			//Check if computedMode is valid
			if( typeof(computedMode) != 'string' || !(computedMode == 'details' || computedMode == 'tile'))
				computedMode = 'details'; //Set default;
			
			//Remove previous possible states
			lsv.removeClass('listview-details listview-tile');
			
			//Some span initialization
			items.children('span')
				.show() 					// Tile mode hides some spans
				.removeClass('secondary') 	// Tile mode adds this tagclass
				.css('margin-left', 'inherit') // Tile mode modifies margin-left
				;
		
			if(computedMode == 'details')
			{
				//Add tagclass
				lsv.addClass('listview-details');
				
				//Hide tree glyphs if present
				items.find('.tree-glyph').show();
				
				//Hide sub-lists visible
				lsv.find('li.node').show();
				
			}else if(computedMode == 'tile'){
				
				//Add tagclass
				lsv.addClass('listview-tile');
				
				//Assign tile width
				items.css({ 'width': settings.tileWidth })
				
				//Hide tree glyphs if present
				items.find('.tree-glyph').hide();
				
				//Hide sub-lists visible
				lsv.find('li.node').hide();
				
				//Set some css of spans
				items.children('span').css({ 
					'margin-left' : firstColumnIncrement,
					'width' : settings.tileWidth - settings.iconSize - 25 //20 is heuristic ;)
				});
				
				//Set secondary spans
				items.find('span:gt(0)').addClass('secondary');
				
				//Hide extra columns
				items.find('span:gt(' + (settings.tileItems - 1) + ')').hide();
			}
			
			lsv.tag('mode', computedMode);
			
			//Update column headers size
			jCaramel.listView.updateColumnHeaderSize(lsv);
			
		},
		
		/**
		 * Gets or sets the selected items on the list
		 * @param {Object} listview
		 * @param {Object} items
		 */
		selectedItems: function(listview, items){
			if (!items) {
				return listview.find('li.selected');
			}else{
				//Remove all checked items
				listview.find('li.selected').removeClass('selected');
				items.addClass('selected');
			}
		},
		
		/**
		 * Sorts the list by the column header passed. 
		 * Sort direction is based on current state.
		 * @param {jQuery} ul List to sort
		 * @param {jQuery} columnHeader to base sort criteria
		 */
		sortByColumnHeader: function(ul, columnHeader){
			
			var lsv = ul.hasClass('listview') ? ul : ul.parents('.listview');
			var colindex = lsv.find('li.column-headers .column-header').index(columnHeader);
			var items = ul.children('li:not(.column-headers)');
			var itemcount = items.size();
			var arr = [];
			var asc = false;
			var n = itemcount;
			var swapped = false;
			var a, b, tmp;
			
			for(var i = 0; i < itemcount; i++) arr[i] = i;
			
			//Check order orientation
			asc = ! ( columnHeader.hasClass('order-asc') );

			
			//Insert each li.node into his sibling
			items.each(function(index){
				var item = jQuery(this);
				if(item.hasClass('node')){
					var owner = item.prev();
					var ul = item.children('ul');
					ul.remove();
					owner.append(ul);
					item.remove();
				}
			});
			
			//Bubble sort ;)
			do{
				swapped = false;
				for ( var i = 0; i <= n - 2; i++ ){
					a = items.eq(arr[i]).find('span:eq(' + (colindex) + ')').text();
					b = items.eq(arr[i + 1]).find('span:eq(' + (colindex) + ')').text();
					
					if(asc){
						if( a > b){
							tmp = arr[i];
							arr[i] = arr[ i + 1];
							arr[i + 1] = tmp;
							swapped = true;
						}
					}else{
						if( a < b){
							tmp = arr[i];
							arr[i] = arr[ i + 1];
							arr[i + 1] = tmp;
							swapped = true;
						}
					}
				}
			}while(swapped)
			
			//Remove items from list
			items.remove();

			//Remove sorted class from listitems spans
			items.find('span.sorted').removeClass('sorted');
			
			//Add items in sorted fashion
			for(var i = 0; i < arr.length; i++){
				var litem = items.eq(arr[i]);
				litem.find('span:eq(' + colindex + ')').addClass('sorted');
				
				ul.append( litem );
				
			}
			
			//Insert each li.node into his sibling
			///*
			items.each(function(index){
				var item = jQuery(this);

				if(item.hasClass('expanded') && item.children('ul').size() > 0){
					var innerul = item.children('ul');
					innerul.remove();
					item.after( jQuery('<li>').addClass('node').append(innerul) );
					
					jCaramel.listView.sortByColumnHeader(innerul, columnHeader);
				}
			});//*/
			
			//Remove order tagclasses
			columnHeader.parent().find('.order-asc').removeClass('order-asc');
			columnHeader.parent().find('.order-desc').removeClass('order-desc')
			columnHeader.parent().find('.glyph-columnheader-desc, .glyph-columnheader-asc').remove();
			
			//Check for asc or desc
			if(!asc){
				columnHeader.addClass('order-desc').append( $('<div>').addClass('glyph-16 glyph-columnheader-desc righty').css({ 'margin-right': 3 }) );
			}else{
				columnHeader.addClass('order-asc').append( $('<div>').addClass('glyph-16 glyph-columnheader-asc righty').css({ 'margin-right': 3 }) );
			}
			
			jCaramel.listView.assignItemHandlers(lsv, items);
				
		},//end columnClick

		/**
		 * Gets or sets a boolean indicating if the list should behave as a tree.
		 * @param {Object} lsv
		 * @param {Object} istree
		 */
		tree: function(lsv, istree){
			
			if(typeof(istree) == 'boolean'){
				
				var items = lsv.find('li:not(.column-headers):not(.node)');
				
				lsv.flag('tree', istree);
				
				if (istree) {
					items.each(function(index){
						
						var li = jQuery(this);
						var count = li.children('.tree-glyph').size();
						if (count == 0) {
							var fold = jQuery('<div>').addClass('glyph-16 tree-glyph lefty');
							
							//Set icon
							if (li.children('ul').size()) {
								fold.addClass('glyph-unfold')
							}
							
							//Add glyph to list-item
							li.prepend(fold);
						}
					});
					
					//Add handlers
					jCaramel.listView.assignItemHandlers(lsv, items);
					
					//Update columns size
					jCaramel.listView.updateColumnHeaderSize(lsv);
				}
				
			}else{
				return lsv.flag('tree');
			}
			
		},
		
		/**
		 * Handles the mouse enter of a tree glyph
		 * @param {Object} evt
		 */
		treeGlyph_MouseEnter: function(evt){
			
		},
		
		/**
		 * Handles the mouse leave of a tree glyph
		 * @param {Object} evt
		 */
		treeGlyph_MouseLeave: function(evt){
			
		},
		
		/**
		 * Handles the click of tree related glyphs
		 */
		treeGlyph_Click: function(evt){
			var g = jQuery(this); //Fold/Unfold glyph
			var li = g.parent();
			var lsv = li.parents('ul.listview').first();
			
			if (g.hasClass('glyph-unfold')) {
				jCaramel.listView.unfold(lsv, li);
			}else{
				jCaramel.listView.fold(lsv, li);
			}
		},
		
		/**
		 * Folds a ListItem that is unfolded. And so its sub-items.
		 * @param {Object} lsv ListView where items belong
		 * @param {Object} li  ListItem to fold
		 */
		fold: function(lsv, li){
			
			var g = li.find('.tree-glyph').first(); //Get glyph
			var node = g.parent().next();
			var ul = g.parent().next().find('ul').first();
			
			if (node.hasClass('node')) {
				
				//Fold sub-nodes
				ul.children('li').each(function(index){
					var li = jQuery(this);
					if(li.flag('expanded')){
						jCaramel.listView.fold(li.parents('ul.listview').first(), li)
					}
				});
				
				ul.hide().remove(); 		//Hide and remove the ul from its li
				g.parent().append(ul); 		//Add the ul back to it's parent li
				g.parent().next().remove(); //Remove the li where ul was hosted
				
				//Flag as not expanded
				li.flag('expanded', false);
				
				//Change glyp to be unfolded
				g.removeClass('glyph-fold').addClass('glyph-unfold');
				
				//Fire event
				jCaramel.fire(lsv, 'fold', [ li, ul]);
			}
		},
		
		/**
		 * Unfolds the specified list item
		 * @param {jQuery} lsv ListView
		 * @param {jQuery} li  ListItem to unfold
		 */
		unfold: function(lsv, li){
			
			var g = li.find('.tree-glyph').first(); //Get glyph	
			var ul = g.parent().find('ul').first();
			var parentlist = ul.parents('ul').first(); 
			var depth = jCaramel.listView.depth(lsv, parentlist) + 1; 
			
			//Fire event
			jCaramel.fire(lsv, 'unfold', [ li, ul]);
			
			//Dettach from li
			ul.remove(); 
			
			//Attach to a li.node
			g.parent().after( jQuery('<li>').addClass('node').append(ul.show()).append($('<ul>')) );
			
			//Set icon as folded
			g.removeClass('glyph-unfold').addClass('glyph-fold');
				
			li.flag('expanded', true);
			ul.tag('depth', depth);
			
			//Update size of first column spans
			jCaramel.listView.updateFirstColumn(lsv, ul);
			
			//Assign handlers to items inside it
			jCaramel.listView.assignItemHandlers(lsv, ul.children('li'));
			
		},
		
		/**
		 * Updates the columns of the listview.
		 * @param {Object} listview ListView to check for columns
		 * @param {Object} columns Columns to create. If not present, columns size will be updated
		 */
		updateColumnHeaderSize: function(lsv){
			
			var firstColumnIncrement 	= jCaramel.listView.firstColumnIncrement(lsv);
			var columns 				= jCaramel.listView.columnHeaders(lsv);
			var mode 					= jCaramel.listView.mode(lsv);
			var firstColumnIndex		= jCaramel.listView.firstColumnIndex(lsv);
			
			//Set size of column headers
			columns.each(function(index){
				var column = jQuery(this);
				if(index == 0){
					column.width(parseInt(column.tag('size')) + firstColumnIncrement);
				}else{
					column.width(parseInt(column.tag('size')));
				}
			});
			
			//Size of items depending on width
			if(mode == 'details'){
				
				//Width of full LI elements
				var liWidth = 0;
				
				//Sum the width of columns
				for(var i = 1; i <= lsv.find('li.column-headers .column-header').size(); i++){
					liWidth += lsv.find('li.column-headers .column-header:nth-child(' + i + ')').outerWidth();
				}

				//Set width of list items
				lsv.find('li').width(liWidth);
				
				//Set the width of column - related spans
				for(var i = 0; i < columns.size(); i++){
					var columnHeader =  columns.eq(i);
					var s = lsv.find('li:not(.column-headers) span:nth-child(' + (i + 1 + firstColumnIndex) + ')');
					var extra = i == 0 ? -firstColumnIncrement - 5 : 0;
					s.width( columnHeader.outerWidth() - ( s.outerWidth() - s.width()) + extra );
				}
				
				//Check for expanded items
				lsv.children('li.node').each(function(index){
					var ul = jQuery(this).children('ul');
					jCaramel.listView.updateFirstColumn(lsv, ul);
				});
				
			}else if( mode = 'tile'){
				
			}
			
		},
		
		/**
		 * Updates the size of the first span on each list-item
		 * @param {Object} lsv
		 * @param {Object} ul
		 */
		updateFirstColumn: function(lsv, ul){
			
			var lsv = ul.parents('ul.listview').first();	
			var parentlist = ul.parents('ul').first(); 
			var depth = jCaramel.listView.depth(lsv, ul); 
			var indent = 20 * (depth);
			var treeitems = ul.children('li:not(.node)');
			var firstColumnIndex = jCaramel.listView.firstColumnIndex(lsv);
			var firstcolumns = treeitems.children('span:nth-child(' + (1 + firstColumnIndex) + ')');
			var firstcol = jCaramel.listView.columnHeaders(lsv).first();
			var firstcolw = parseInt(firstcol.tag('size'));
			
			//Alter size of first spans
			firstcolumns.width(firstcolw - indent);
			
			//Indent tree items
			treeitems.css('padding-left', indent);
			 
			//Reduce list item width
			treeitems.width(lsv.find('.column-headers').width() - indent);
			
			//Check for expanded items
			
			ul.children('li.node').each(function(index){
				var ul = jQuery(this).children('ul').first();
				jCaramel.listView.updateFirstColumn(lsv, ul);
			});
		}
		
	};//End listview namespace
	
/**
 * listivew - Converts UL in listview
 * @param {Object} a Creation options | method to invoke
 * @param {Object} b First parameter to pass to method to invoke
 */
jQuery.fn.listview = function(a, b){
	
	if (typeof(a) == 'string'){
		return jCaramel.listView[a](this, b);
	}else{
		settings = jQuery.extend({
			
			// Puts or removes checkboxes from items
			checkboxes: false,
			
			// One empty column by default
			columns : null,
			
			// Width and height of icons in list
			iconSize : 0,
			
			//Default mode
			mode: 'details',
			
			// Width of the items when in tile mode
			tileWidth : 230,
			
			// Columns to show on items when in tile mode
			tileItems : 3,
			
			//Hides columns in case it's needed
			hideColumns: false,
			
			
		}, a);
		
		//Create the listview
		jCaramel.listView._create(this, settings);
		
		return this;
	}
};

/**
 * Makes the items ready for listview usage
 * @param {Object} lsv
 */
jQuery.fn.makeitem = function(lsv){
	
	var checks = lsv.listview('checkboxes');
	var tr = lsv.listview('tree');
	
	this.each(function(index){
		var item = jQuery(this);
		if(checks && item.children('.glyph-checkbox-unchecked, .glyph-checkbox-checked').size() == 0)
			item.prepend( jQuery('<div>').addClass('glyph-16 glyph-checkbox-unchecked lefty') );
			
		if(tr && item.children('.tree-glyph').size() == 0){
			var fold = jQuery('<div>').addClass('glyph-16 tree-glyph lefty');
							
			//Set icon
			if (item.children('ul').size()) {
				fold.addClass('glyph-unfold')
			}
			
			//Add glyph to list-item
			item.prepend(fold);
		}
			
	});
	
	return this;
}
